package dal

import (
	"context"
	"encoding/json"

	"code.byted.org/bytertc/whiteboard_server/biz/dal/ddl"
	"code.byted.org/bytertc/whiteboard_server/biz/dal/spec"
	"code.byted.org/bytertc/whiteboard_server/biz/pkg/biz_error"
	"github.com/pkg/errors"
	"gorm.io/plugin/dbresolver"
)

const (
	WebsocketConnectPrefix = "wsconn:"
)

func (r *repo) GetRoom(ctx context.Context, unique spec.RoomUnique) (*ddl.Rooms, error) {
	var bs []ddl.Rooms
	query := r.db.WithContext(ctx).Clauses(dbresolver.Write).Table(ddl.TableRooms).
		Where("app_id = ? and room_id = ?", unique.GetAppId(), unique.GetRoomId())
	err := query.Find(&bs).Error
	if err != nil {
		return nil, biz_error.DatabaseError.Wrap(errors.WithStack(err))
	}
	if len(bs) == 0 {
		return nil, nil
	}
	return &bs[0], nil
}

func (r *repo) CreateRoom(ctx context.Context, unique spec.BoardUnique) error {
	room := &ddl.Rooms{
		AppId:         unique.GetAppId(),
		RoomId:        unique.GetRoomId(),
		ActiveBoardId: unique.GetBoardId(),
	}
	err := r.db.WithContext(ctx).Table(ddl.TableRooms).Create(room).Error
	if IsDuplicateError(err) {
		return biz_error.Conflict.Wrap(errors.WithStack(err))
	}
	return err
}
func (r *repo) RoomExist(ctx context.Context, unique spec.BoardUnique) (bool, error) {
	var bs []ddl.Rooms
	query := r.db.WithContext(ctx).Table(ddl.TableRooms).
		Where("app_id = ? and room_id = ?", unique.GetAppId(), unique.GetRoomId())
	err := query.Find(&bs).Error
	if err != nil {
		return false, biz_error.DatabaseError.Wrap(errors.WithStack(err))
	}
	if len(bs) == 0 {
		return false, nil
	}
	return true, nil
}

func (r *repo) UpdateActiveBoardId(ctx context.Context, unique spec.RoomUnique, activeBoardId int32) error {
	err := r.db.WithContext(ctx).Table(ddl.TableRooms).
		Where("app_id = ? and room_id = ?",
			unique.GetAppId(), unique.GetRoomId()).
		Update("active_board_id", activeBoardId).Error
	if err != nil {
		return biz_error.DatabaseError.Wrap(errors.WithStack(err))
	}
	return nil

}
func (r *repo) CloseRoom(ctx context.Context, unique spec.RoomUnique) error {
	err := r.db.WithContext(ctx).Table(ddl.TableRooms).
		Where("app_id = ? and room_id = ?",
			unique.GetAppId(), unique.GetRoomId()).
		Update("status", ddl.Inactive).Error
	if err != nil {
		return biz_error.DatabaseError.Wrap(errors.WithStack(err))
	}
	return nil
}

func (r *repo) GetWsParam(ctx context.Context, appID, roomID string) (*ddl.WsParam, error) {
	val, err := r.cache.Get(ctx, getWebsocketConnectKey(appID, roomID))
	if err != nil {
		if IsNotFoundError(err) {
			return nil, nil
		}
		return nil, err
	}
	res := &ddl.WsParam{}
	err = json.Unmarshal([]byte(val), res)
	if err != nil {
		return nil, err
	}
	return res, nil
}

func getWebsocketConnectKey(appID, roomID string) string {
	return WebsocketConnectPrefix + appID + ":" + roomID
}
